package com.carnation._synchronized_utility;

import java.util.concurrent.*;

/**
 * <p>
 * CountDownLatch：允许一个或多个线程等待其它子线程的操作执行完毕后再执行后续的操作。
 * 一：实现原理：
 * 1：核心方法：{@link CountDownLatch#countDown()}、{@link CountDownLatch#await()}
 * 2：{@link CountDownLatch#await()}：用来阻塞线程，直到计数器的值为0。
 * 3：{@link CountDownLatch#countDown()}：执行计数器 - 1操作。
 * 4：实现方式：借用AQS共享锁，CountDownLatch主要是通过计数器state来控制是否可以执行其他操作，如果不能就通过LockSupport.park()方法挂起线程，直到其他线程执行完毕后唤醒它。
 * 5：缺点：只能使用一次，计数器不能被reset。
 * 二：适用场景：子线程的任务没有依赖顺序，主线程可用于汇聚子线程的执行结果。---> 也可以使用{@link com.carnation._executor.CompletableFutureTest}
 * e.g：我们要读取处理6个文件，这6个任务都是没有执行顺序依赖的任务，但是我们需要返回给用户的时候将这几个文件的处理的结果进行统计整理。
 * 三：开源框架中的应用：
 * 1：Spring-Context，
 * 2：Zookeeper：(ZooKeeperServerMain类使用CountDownLatch hang住服务端的请求服务，当服务端有错误的时候CountDownLatch#countDown，服务端hang住的请求会继续，即做shutdown处理)
 *               参考：{org.apache.zookeeper.server.ZooKeeperServerMain}的128行
 * </p>
 *
 * @author: Sunny
 * @date: 2021/2/4
 * @version: v1.0.0
 */
public class CountDownLatchTest {

    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService executorService = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
        for (int i = 0; i < 10; i++) {
            final int time = i;
            executorService.submit(() -> {
                try {
                    System.out.println("子线程" + Thread.currentThread().getName() + "正在赶路");
                    TimeUnit.SECONDS.sleep(time);
                    System.out.println("子线程" + Thread.currentThread().getName() + "到公司了");
                    // 调用latch的countDown方法使计数器 - 1
                    latch.countDown();
                    System.out.println("子线程" + Thread.currentThread().getName() + "开始工作");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        try {
            System.out.println("门卫等待员工上班中...");
            // 主线程阻塞等待计数器归零
            latch.await();
            System.out.println("员工都来了,门卫去休息了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

}
